<template>
  <div class="app-container">
    <el-row :gutter="20">
      <!-- 用户列表 -->
      <el-col :span="6">
        <el-card class="box-card">
          <div slot="header" class="clearfix">
            <span>用户列表</span>
            <el-input
              v-model="searchValue"
              placeholder="搜索用户"
              style="margin-top: 10px"
              clearable
              @clear="loadUserList"
              @keyup.enter.native="searchUsers"
            >
              <el-button slot="append" icon="el-icon-search" @click="searchUsers"></el-button>
            </el-input>
          </div>
          <div class="user-list">
            <div
              v-for="(user, index) in userList"
              :key="index"
              class="user-item"
              :class="{ 'active': currentUser && currentUser.userId === user.userId }"
              @click="selectUser(user)"
            >
              <div class="user-avatar">
                <el-avatar :size="40" :src="user.avatar || defaultAvatar">{{ user.nickName.substr(0, 1) }}</el-avatar>
                <el-badge v-if="user.unreadCount > 0" :value="user.unreadCount" class="unread-badge"></el-badge>
              </div>
              <div class="user-info">
                <div class="user-name">{{ user.nickName }}</div>
                <div class="last-message">{{ user.lastMessage || '暂无消息' }}</div>
              </div>
              <div class="message-time" v-if="user.lastMessageTime">{{ formatTime(user.lastMessageTime) }}</div>
            </div>
            <div v-if="userList.length === 0" class="empty-list">
              暂无用户咨询
            </div>
          </div>
        </el-card>
      </el-col>

      <!-- 聊天区域 -->
      <el-col :span="18">
        <el-card class="box-card chat-container" v-if="currentUser">
          <div slot="header" class="clearfix">
            <span>与 {{ currentUser.nickName }} 聊天中</span>
            <span class="user-status">{{ currentUser.online ? '在线' : '离线' }}</span>
          </div>
          <div class="chat-content" ref="chatContent">
            <div v-if="chatLoading" class="chat-loading">
              <el-spinner></el-spinner>
              <span>加载中...</span>
            </div>
            <div v-if="messageList.length === 0 && !chatLoading" class="empty-chat">
              暂无消息记录，开始聊天吧
            </div>
            <div v-for="(msg, index) in messageList" :key="index" class="message-item" :class="{ 'self': msg.fromUserId === serviceId }">
              <div class="message-avatar">
                <el-avatar :size="40" :src="msg.fromUserId === serviceId ? serviceAvatar : currentUser.avatar || defaultAvatar">
                  {{ msg.fromUserId === serviceId ? 'S' : currentUser.nickName.substr(0, 1) }}
                </el-avatar>
              </div>
              <div class="message-content">
                <div class="message-info">
                  <span class="message-sender">{{ msg.fromUserId === serviceId ? '客服' : currentUser.nickName }}</span>
                  <span class="message-time">{{ formatTime(msg.createTime) }}</span>
                </div>
                <div class="message-bubble" :class="{ 'self': msg.fromUserId === serviceId }">
                  <!-- 文本消息 -->
                  <span v-if="msg.messageType === '0'">{{ msg.content }}</span>
                  
                  <!-- 图片消息 -->
                  <div v-if="msg.messageType === '1'" class="image-message">
                    <el-image 
                      :src="msg.content" 
                      :preview-src-list="[msg.content]"
                      fit="cover"
                      style="max-width: 200px; max-height: 200px;"
                    ></el-image>
                  </div>
                  
                  <!-- 语音消息 -->
                  <div v-if="msg.messageType === '2'" class="voice-message" @click="playVoice(msg.content)">
                    <i class="el-icon-microphone"></i>
                    <span>语音消息</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="chat-input">
            <div class="quick-reply-panel" v-if="showQuickReply">
              <div class="quick-reply-categories">
                <div 
                  v-for="category in quickReplyCategories" 
                  :key="category"
                  class="category-item"
                  :class="{'active': currentCategory === category}"
                  @click="selectCategory(category)"
                >
                  {{category}}
                </div>
              </div>
              <div class="quick-reply-list">
                <div 
                  v-for="(reply, index) in filteredQuickReplies" 
                  :key="index"
                  class="reply-item"
                  @click="useQuickReply(reply.content)"
                >
                  {{reply.content}}
                </div>
              </div>
            </div>
            
            <el-input
              type="textarea"
              :rows="3"
              placeholder="请输入消息内容..."
              v-model="inputMessage"
              @keyup.ctrl.enter.native="sendMessage"
            ></el-input>
            <div class="input-actions">
              <el-button size="small" type="text" @click="toggleQuickReply">
                <i class="el-icon-s-order"></i> 快捷回复
              </el-button>
              <el-upload
                class="upload-demo"
                action="/api/chat/upload"
                :headers="headers"
                :data="{type: 'image'}"
                :show-file-list="false"
                :before-upload="beforeUpload"
                :on-success="handleImageSuccess"
              >
                <el-button size="small" type="text">
                  <i class="el-icon-picture-outline"></i> 图片
                </el-button>
              </el-upload>
              <el-button type="primary" @click="sendMessage" :disabled="!inputMessage.trim()">发送</el-button>
            </div>
          </div>
        </el-card>
        <el-card v-else class="box-card chat-placeholder">
          <div class="placeholder-content">
            <i class="el-icon-chat-dot-square"></i>
            <p>请选择一个用户开始聊天</p>
          </div>
        </el-card>
      </el-col>
    </el-row>
    
    <!-- 快捷回复管理对话框 -->
    <el-dialog title="快捷回复管理" :visible.sync="quickReplyDialogVisible" width="600px">
      <div class="quick-reply-dialog">
        <div class="quick-reply-form">
          <el-form :model="quickReplyForm" :rules="quickReplyRules" ref="quickReplyForm" label-width="80px">
            <el-form-item label="分类" prop="category">
              <el-select v-model="quickReplyForm.category" placeholder="请选择分类">
                <el-option
                  v-for="item in quickReplyCategories"
                  :key="item"
                  :label="item"
                  :value="item">
                </el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="内容" prop="content">
              <el-input type="textarea" :rows="3" v-model="quickReplyForm.content" placeholder="请输入回复内容"></el-input>
            </el-form-item>
            <el-form-item label="排序" prop="sortOrder">
              <el-input-number v-model="quickReplyForm.sortOrder" :min="1" :max="99"></el-input-number>
            </el-form-item>
          </el-form>
          <div class="form-actions">
            <el-button @click="resetQuickReplyForm">取消</el-button>
            <el-button type="primary" @click="saveQuickReply">保存</el-button>
          </div>
        </div>
        
        <div class="quick-reply-table">
          <el-table :data="quickReplies" style="width: 100%" max-height="400">
            <el-table-column prop="category" label="分类" width="100"></el-table-column>
            <el-table-column prop="content" label="内容">
              <template slot-scope="scope">
                <div class="reply-content-cell">{{scope.row.content}}</div>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="120">
              <template slot-scope="scope">
                <el-button type="text" size="small" @click="editQuickReply(scope.row)">编辑</el-button>
                <el-button type="text" size="small" @click="deleteQuickReply(scope.row)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
          
          <div class="add-button">
            <el-button type="primary" icon="el-icon-plus" @click="addQuickReply">新增快捷回复</el-button>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { getUserList, getChatHistory, sendChatMessage, markMessageAsRead, 
  getQuickReplyList, getQuickReplyByCategory, getQuickReplyCategories, 
  addQuickReply, updateQuickReply, deleteQuickReply } from "@/api/chat/service";
import { getToken } from "@/utils/auth";

export default {
  name: "ChatService",
  data() {
    return {
      // 用户列表
      userList: [],
      // 当前选中的用户
      currentUser: null,
      // 消息列表
      messageList: [],
      // 输入的消息
      inputMessage: "",
      // 搜索值
      searchValue: "",
      // 客服ID
      serviceId: this.$store.getters.userId,
      // 客服头像
      serviceAvatar: this.$store.getters.avatar,
      // 默认头像
      defaultAvatar: require("@/assets/images/profile.jpg"),
      // 聊天加载状态
      chatLoading: false,
      // 分页参数
      queryParams: {
        pageNum: 1,
        pageSize: 20
      },
      // WebSocket连接
      socket: null,
      // 上传头部
      headers: {
        Authorization: "Bearer " + getToken()
      },
      // 音频播放器
      audioPlayer: null,
      // 心跳相关
      lastHeartbeatTime: null,
      heartbeatTimer: null,
      reconnecting: false,
      reconnectAttempts: 0,
      // 快捷回复相关
      showQuickReply: false,
      quickReplies: [],
      quickReplyCategories: [],
      currentCategory: '',
      quickReplyDialogVisible: false,
      quickReplyForm: {
        id: null,
        category: '',
        content: '',
        sortOrder: 1
      },
      quickReplyRules: {
        category: [{ required: true, message: '请选择分类', trigger: 'change' }],
        content: [{ required: true, message: '请输入回复内容', trigger: 'blur' }]
      }
    };
  },
  computed: {
    filteredQuickReplies() {
      if (!this.currentCategory) return this.quickReplies;
      return this.quickReplies.filter(item => item.category === this.currentCategory);
    }
  },
  created() {
    this.loadUserList();
    this.initWebSocket();
    this.loadQuickReplies();
    this.loadQuickReplyCategories();
  },
  beforeDestroy() {
    this.closeWebSocket();
  },
  methods: {
    /** 加载用户列表 */
    loadUserList() {
      getUserList().then(response => {
        this.userList = response.data;
      });
    },
    
    /** 搜索用户 */
    searchUsers() {
      getUserList({ nickName: this.searchValue }).then(response => {
        this.userList = response.data;
      });
    },
    
    /** 选择用户 */
    selectUser(user) {
      this.currentUser = user;
      this.messageList = [];
      this.loadChatHistory();
      
      // 标记消息为已读
      if (user.unreadCount > 0) {
        markMessageAsRead(user.userId).then(() => {
          // 更新用户列表中的未读数
          user.unreadCount = 0;
        });
      }
    },
    
    /** 加载聊天历史记录 */
    loadChatHistory() {
      if (!this.currentUser) return;
      
      this.chatLoading = true;
      getChatHistory({
        userId: this.currentUser.userId,
        pageNum: this.queryParams.pageNum,
        pageSize: this.queryParams.pageSize
      }).then(response => {
        this.messageList = response.rows;
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }).finally(() => {
        this.chatLoading = false;
      });
    },
    
    /** 初始化WebSocket连接 */
    initWebSocket() {
      const token = getToken();
      if (!token) return;
      
      // 关闭现有连接
      this.closeWebSocket();
      
      // 创建WebSocket连接
      const wsUrl = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/websocket/chat/${token}`;
      this.socket = new WebSocket(wsUrl);
      
      // 连接建立时的回调
      this.socket.onopen = () => {
        console.log("WebSocket连接已建立");
        // 连接成功后，发送心跳包
        this.startHeartbeat();
      };
      
      // 收到消息的回调
      this.socket.onmessage = (event) => {
        try {
          const message = JSON.parse(event.data);
          
          // 处理不同类型的消息
          if (message.type === "heartbeat" || message.type === "heartbeat_response") {
            // 心跳消息，更新最后心跳时间
            this.lastHeartbeatTime = new Date().getTime();
            return;
          }
          
          if (message.type === "connected") {
            // 连接成功消息，不需要处理
            return;
          }
          
          // 如果是当前用户的消息，直接添加到消息列表
          if (this.currentUser && message.fromUserId === this.currentUser.userId) {
            this.messageList.push(message);
            this.$nextTick(() => {
              this.scrollToBottom();
            });
            
            // 标记为已读
            markMessageAsRead(message.id).then(() => {
              // 更新消息状态为已读
              message.readStatus = "1";
              message.sendStatus = "3";
            });
          }
          
          // 更新用户列表
          const user = this.userList.find(u => u.userId === message.fromUserId);
          if (user) {
            // 如果不是当前聊天的用户，增加未读数
            if (!this.currentUser || this.currentUser.userId !== user.userId) {
              user.unreadCount = (user.unreadCount || 0) + 1;
            }
            
            // 更新最后一条消息
            if (message.messageType === "0") {
              user.lastMessage = message.content;
            } else if (message.messageType === "1") {
              user.lastMessage = "[图片]";
            } else if (message.messageType === "2") {
              user.lastMessage = "[语音]";
            }
            
            user.lastMessageTime = message.createTime;
            
            // 将该用户移到列表顶部
            this.userList = this.userList.filter(u => u.userId !== user.userId);
            this.userList.unshift(user);
          } else {
            // 如果是新用户，重新加载用户列表
            this.loadUserList();
          }
        } catch (error) {
          console.error("解析消息失败", error);
        }
      };
      
      // 连接关闭的回调
      this.socket.onclose = () => {
        console.log("WebSocket连接已关闭");
        this.stopHeartbeat();
        // 尝试重连
        this.reconnectWebSocket();
      };
      
      // 连接错误的回调
      this.socket.onerror = (error) => {
        console.error("WebSocket连接错误", error);
        this.stopHeartbeat();
        // 尝试重连
        this.reconnectWebSocket();
      };
    },
    
    // 开始心跳检测
    startHeartbeat() {
      this.stopHeartbeat();
      this.lastHeartbeatTime = new Date().getTime();
      
      // 每30秒发送一次心跳包
      this.heartbeatTimer = setInterval(() => {
        if (this.socket && this.socket.readyState === WebSocket.OPEN) {
          // 发送心跳包
          this.socket.send(JSON.stringify({
            type: "heartbeat",
            timestamp: new Date().getTime()
          }));
          
          // 检查最后心跳时间，如果超过60秒没有收到心跳响应，认为连接已断开
          const now = new Date().getTime();
          if (now - this.lastHeartbeatTime > 60000) {
            console.warn("心跳超时，重新连接");
            this.reconnectWebSocket();
          }
        }
      }, 30000);
    },
    
    // 停止心跳检测
    stopHeartbeat() {
      if (this.heartbeatTimer) {
        clearInterval(this.heartbeatTimer);
        this.heartbeatTimer = null;
      }
    },
    
    // 重连WebSocket
    reconnectWebSocket() {
      // 如果已经在重连中，直接返回
      if (this.reconnecting) return;
      
      this.reconnecting = true;
      this.reconnectAttempts = this.reconnectAttempts || 0;
      
      // 最大重连次数
      const maxReconnectAttempts = 10;
      // 重连间隔时间，使用指数退避算法
      const reconnectDelay = Math.min(30000, Math.pow(2, this.reconnectAttempts) * 1000 + Math.random() * 1000);
      
      if (this.reconnectAttempts < maxReconnectAttempts) {
        console.log(`WebSocket ${this.reconnectAttempts + 1}次重连，${reconnectDelay}ms后重试`);
        
        setTimeout(() => {
          this.reconnectAttempts++;
          this.initWebSocket();
          this.reconnecting = false;
        }, reconnectDelay);
      } else {
        console.error("WebSocket重连失败，已达到最大重试次数");
        this.reconnecting = false;
        
        // 提示用户刷新页面
        this.$notify.error({
          title: "连接断开",
          message: "聊天连接已断开，请刷新页面重试",
          duration: 0
        });
      }
    },
    
    /** 关闭WebSocket连接 */
    closeWebSocket() {
      this.stopHeartbeat();
      if (this.socket) {
        // 避免触发重连
        const socket = this.socket;
        this.socket = null;
        
        // 如果连接处于打开状态，则关闭连接
        if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
          socket.close();
        }
      }
    },
    
    /** 播放语音消息 */
    playVoice(url) {
      if (this.audioPlayer) {
        this.audioPlayer.pause();
        this.audioPlayer = null;
      }
      
      this.audioPlayer = new Audio(url);
      this.audioPlayer.play();
    },
    
    /** 滚动到底部 */
    scrollToBottom() {
      const chatContent = this.$refs.chatContent;
      if (chatContent) {
        chatContent.scrollTop = chatContent.scrollHeight;
      }
    },
    
    /** 上传前校验 */
    beforeUpload(file) {
      const isImage = file.type.indexOf("image/") === 0;
      const isLt2M = file.size / 1024 / 1024 < 2;
      
      if (!isImage) {
        this.$message.error("只能上传图片文件!");
        return false;
      }
      if (!isLt2M) {
        this.$message.error("图片大小不能超过 2MB!");
        return false;
      }
      return true;
    },
    
    /** 图片上传成功回调 */
    handleImageSuccess(res, file) {
      if (res.code === 200) {
        const message = {
          fromUserId: this.serviceId,
          toUserId: this.currentUser.userId,
          content: res.data.url,
          messageType: "1", // 图片消息
          createTime: new Date()
        };
        
        // 添加到本地消息列表
        this.messageList.push(message);
        this.$nextTick(() => {
          this.scrollToBottom();
        });
        
        // 发送消息到服务器
        sendChatMessage(message).then(() => {
          // 更新用户列表中的最后一条消息
          const user = this.userList.find(u => u.userId === this.currentUser.userId);
          if (user) {
            user.lastMessage = "[图片]";
            user.lastMessageTime = new Date();
            
            // 将该用户移到列表顶部
            this.userList = this.userList.filter(u => u.userId !== user.userId);
            this.userList.unshift(user);
          }
        });
      } else {
        this.$message.error("上传图片失败");
      }
    },
    
    /** 发送消息 */
    sendMessage() {
      if (!this.inputMessage.trim() || !this.currentUser) return;
      
      // 创建消息对象
      const message = {
        type: "chat",
        fromUserId: this.serviceId,
        toUserId: this.currentUser.userId,
        content: this.inputMessage,
        messageType: "0", // 文本消息
        createTime: new Date(),
        sendStatus: "0" // 发送中
      };
      
      // 先添加到本地消息列表
      this.messageList.push(message);
      this.$nextTick(() => {
        this.scrollToBottom();
      });
      
      // 清空输入框
      const content = this.inputMessage;
      this.inputMessage = "";
      
      // 检查WebSocket连接状态
      if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
        console.error("WebSocket连接已断开，无法发送消息");
        // 更新消息状态为发送失败
        message.sendStatus = "4"; // 4表示发送失败
        
        // 提示用户
        this.$message.error("消息发送失败，连接已断开");
        
        // 尝试重连
        this.reconnectWebSocket();
        return;
      }
      
      // 发送消息
      this.socket.send(JSON.stringify(message));
      
      // 更新用户列表中的最后一条消息
      const user = this.userList.find(u => u.userId === this.currentUser.userId);
      if (user) {
        user.lastMessage = content;
        user.lastMessageTime = new Date();
        
        // 将该用户移到列表顶部
        this.userList = this.userList.filter(u => u.userId !== user.userId);
        this.userList.unshift(user);
      }
      
      // 发送消息到服务器
      sendChatMessage(message).then((response) => {
        // 更新消息ID
        message.id = response.data;
        message.sendStatus = "1"; // 已发送
        
        // 如果接收者在线，更新状态为已送达
        if (this.currentUser.online) {
          message.sendStatus = "2"; // 已送达
        }
      }).catch((error) => {
        console.error("发送消息失败", error);
        message.sendStatus = "4"; // 发送失败
        this.$message.error("消息发送失败，请重试");
      });
    },
    
    /** 格式化时间 */
    formatTime(time) {
      if (!time) return "";
      
      const date = new Date(time);
      const now = new Date();
      
      // 今天的消息只显示时间
      if (date.toDateString() === now.toDateString()) {
        return this.formatTimeOnly(date);
      }
      
      // 昨天的消息显示"昨天"
      const yesterday = new Date(now);
      yesterday.setDate(now.getDate() - 1);
      if (date.toDateString() === yesterday.toDateString()) {
        return `昨天 ${this.formatTimeOnly(date)}`;
      }
      
      // 今年的消息显示月日
      if (date.getFullYear() === now.getFullYear()) {
        return `${date.getMonth() + 1}月${date.getDate()}日 ${this.formatTimeOnly(date)}`;
      }
      
      // 其他显示完整日期
      return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()} ${this.formatTimeOnly(date)}`;
    },
    
    /** 格式化时间（只有时分） */
    formatTimeOnly(date) {
      return `${this.padZero(date.getHours())}:${this.padZero(date.getMinutes())}`;
    },
    
    /** 数字补零 */
    padZero(num) {
      return num < 10 ? `0${num}` : num;
    },
    
    /** 加载快捷回复列表 */
    loadQuickReplies() {
      getQuickReplyList().then(response => {
        this.quickReplies = response.data;
      });
    },
    
    /** 加载快捷回复分类 */
    loadQuickReplyCategories() {
      getQuickReplyCategories().then(response => {
        this.quickReplyCategories = response.data;
        if (this.quickReplyCategories.length > 0) {
          this.currentCategory = this.quickReplyCategories[0];
        }
      });
    },
    
    /** 切换快捷回复面板 */
    toggleQuickReply() {
      this.showQuickReply = !this.showQuickReply;
    },
    
    /** 选择快捷回复分类 */
    selectCategory(category) {
      this.currentCategory = category;
    },
    
    /** 使用快捷回复 */
    useQuickReply(content) {
      this.inputMessage = content;
      this.showQuickReply = false;
    },
    
    /** 打开快捷回复管理对话框 */
    openQuickReplyDialog() {
      this.quickReplyDialogVisible = true;
    },
    
    /** 添加快捷回复 */
    addQuickReply() {
      this.resetQuickReplyForm();
      this.quickReplyDialogVisible = true;
    },
    
    /** 编辑快捷回复 */
    editQuickReply(row) {
      this.quickReplyForm = { ...row };
      this.quickReplyDialogVisible = true;
    },
    
    /** 删除快捷回复 */
    deleteQuickReply(row) {
      this.$confirm('确认删除该快捷回复吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteQuickReply(row.id).then(() => {
          this.$message.success('删除成功');
          this.loadQuickReplies();
        });
      }).catch(() => {});
    },
    
    /** 保存快捷回复 */
    saveQuickReply() {
      this.$refs.quickReplyForm.validate(valid => {
        if (!valid) return;
        
        if (this.quickReplyForm.id) {
          // 更新
          updateQuickReply(this.quickReplyForm).then(() => {
            this.$message.success('更新成功');
            this.quickReplyDialogVisible = false;
            this.loadQuickReplies();
          });
        } else {
          // 新增
          addQuickReply(this.quickReplyForm).then(() => {
            this.$message.success('添加成功');
            this.quickReplyDialogVisible = false;
            this.loadQuickReplies();
          });
        }
      });
    },
    
    /** 重置快捷回复表单 */
    resetQuickReplyForm() {
      this.quickReplyForm = {
        id: null,
        category: this.quickReplyCategories.length > 0 ? this.quickReplyCategories[0] : '',
        content: '',
        sortOrder: 1
      };
      if (this.$refs.quickReplyForm) {
        this.$refs.quickReplyForm.resetFields();
      }
    }
  }
};
</script>

<style scoped>
.app-container {
  height: calc(100vh - 120px);
}

.box-card {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.user-list {
  flex: 1;
  overflow-y: auto;
  margin-top: 10px;
}

.user-item {
  display: flex;
  padding: 10px;
  border-bottom: 1px solid #eee;
  cursor: pointer;
  position: relative;
}

.user-item:hover {
  background-color: #f5f7fa;
}

.user-item.active {
  background-color: #ecf5ff;
}

.user-avatar {
  position: relative;
  margin-right: 10px;
}

.unread-badge {
  position: absolute;
  top: -5px;
  right: -5px;
}

.user-info {
  flex: 1;
  overflow: hidden;
}

.user-name {
  font-weight: bold;
  margin-bottom: 5px;
}

.last-message {
  color: #999;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 150px;
}

.message-time {
  font-size: 12px;
  color: #999;
}

.chat-container {
  display: flex;
  flex-direction: column;
}

.chat-content {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  min-height: 400px;
  max-height: calc(100vh - 280px);
}

.message-item {
  display: flex;
  margin-bottom: 15px;
}

.message-item.self {
  flex-direction: row-reverse;
}

.message-avatar {
  margin: 0 10px;
}

.message-content {
  max-width: 70%;
}

.message-info {
  margin-bottom: 5px;
}

.message-sender {
  font-weight: bold;
  margin-right: 10px;
}

.message-time {
  font-size: 12px;
  color: #999;
}

.message-bubble {
  padding: 10px;
  border-radius: 4px;
  background-color: #f2f2f2;
  word-break: break-all;
}

.message-bubble.self {
  background-color: #ecf5ff;
}

.chat-input {
  margin-top: 10px;
}

.input-actions {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
}

.chat-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
}

.placeholder-content {
  text-align: center;
  color: #909399;
}

.placeholder-content i {
  font-size: 48px;
  margin-bottom: 10px;
}

.empty-list, .empty-chat {
  text-align: center;
  color: #909399;
  padding: 20px;
}

.chat-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #909399;
}

.voice-message {
  display: flex;
  align-items: center;
  cursor: pointer;
}

.voice-message i {
  margin-right: 5px;
}

.user-status {
  margin-left: 10px;
  font-size: 12px;
  color: #67c23a;
}

/* 快捷回复样式 */
.quick-reply-panel {
  background-color: #fff;
  border: 1px solid #eee;
  border-radius: 4px;
  margin-bottom: 10px;
  height: 200px;
  display: flex;
}

.quick-reply-categories {
  width: 100px;
  border-right: 1px solid #eee;
  overflow-y: auto;
}

.category-item {
  padding: 10px;
  cursor: pointer;
  text-align: center;
  border-bottom: 1px solid #f5f5f5;
}

.category-item:hover {
  background-color: #f5f7fa;
}

.category-item.active {
  background-color: #ecf5ff;
  color: #409EFF;
}

.quick-reply-list {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
}

.reply-item {
  padding: 8px 12px;
  margin-bottom: 8px;
  border-radius: 4px;
  background-color: #f5f7fa;
  cursor: pointer;
}

.reply-item:hover {
  background-color: #ecf5ff;
}

/* 快捷回复对话框样式 */
.quick-reply-dialog {
  display: flex;
  flex-direction: column;
}

.quick-reply-form {
  margin-bottom: 20px;
}

.form-actions {
  text-align: right;
  margin-top: 10px;
}

.quick-reply-table {
  margin-top: 20px;
}

.reply-content-cell {
  max-height: 60px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.add-button {
  margin-top: 10px;
  text-align: center;
}
</style> 